import { Middleware, IMiddleware, Inject } from '@midwayjs/core';
import { NextFunction, Context } from '@midwayjs/koa';
import { Decrypt, Encrypt } from '@/utils/aes'; // Decrypt
import { RedisService } from '@midwayjs/redis';
import { RedisEnum } from '@utils/enum';

// 加密白名单
const whiteList = [
  '/',
  '/captchaImage',
  '/public',
  '/student/importTemplate',
  '/ip',
  '/mqtt',
  '/wristband_adv/list_wb_data',
  '/wristband_history/save',
  '/wristband_adv/deleteData',
  '/school/upload',
  '/xbm/convert',
  '/xbm/xbmToMqtt',
  '/ip/getLocalTime',
  '/ip/getTestLocalTime',
];

@Middleware()
export class EncryptMiddleware implements IMiddleware<Context, NextFunction> {
  @Inject()
  redisService: RedisService;

  resolve() {
    return async (ctx: Context, next: NextFunction) => {
      // 获取路由地址
      const routerUrl = ctx.request.url.split('?')[0];

      // 如果是白名单中的地址，直接放行
      if (
        whiteList.includes(routerUrl) ||
        routerUrl.includes('/student/importTemplate') ||
        routerUrl.includes('/importData') ||
        routerUrl.includes('/export') ||
        routerUrl.includes('/file') ||
        routerUrl.includes('/profile/avatar') ||
        routerUrl.includes('/ip/getLocalTime') ||
        routerUrl.includes('/firmware_wristband/downloadUrl') ||
        routerUrl.includes('/mqtt') ||
        routerUrl.includes('/wristband_adv/list_wb_data') ||
        routerUrl.includes('/wristband_history/save') ||
        routerUrl.includes('/wristband_adv/deleteData') ||
        routerUrl.includes('/school/upload'),
        routerUrl.includes('/xbm/convert'),
        routerUrl.includes('/xbm/xbmToMqtt')
      ) {
        await next();
      } else {
        const temp = await this.redisService.get(
          `${RedisEnum.SYS_CONFIG_KEY}sys.interface.enable`
        );
        const isOpenCrypt = temp === null ? true : JSON.parse(temp);

        const requestMethod = ctx.method.toUpperCase();

        // 如果开启了加密且请求方法在白名单之外
        if(isOpenCrypt && !whiteList.includes(routerUrl)) {
          // 确保 Query 参数被正确解析（所有方法）
          ctx.query = ctx.request.query;
          console.log('Query 参数:', ctx.query);

          // 统一处理加密请求体（POST/PUT/PATCH）
          if (['POST', 'PUT', 'PATCH'].includes(requestMethod)) {
            const body: any = ctx.request.body;

            // 文件上传请求特殊处理（跳过加密）
            if (ctx.is('multipart')) {
              console.log('跳过文件上传请求的加密检查');
              await next();
              return;
            }

            // 非文件请求必须包含加密数据
            if (!body?.param) {
              ctx.throw(400, 'Missing encrypted data in request');
            }

            try {
              ctx.request.body = JSON.parse(Decrypt(body.param));
              console.log('解密后的 Body:', ctx.request.body);
            } catch (error) {
              console.error('解密失败:', error);
              ctx.throw(400, 'Request decryption failed');
            }
          }

          // 统一执行后续中间件
          await next();

          // 统一加密响应（所有方法）
          if (ctx.response.body) {
            ctx.response.body = Encrypt(JSON.stringify(ctx.response.body));
          }

        } else {
          // 加密关闭时的降级处理
          if (['POST', 'PUT', 'PATCH'].includes(requestMethod)) {
            const body: any = ctx.request.body;
            if (body?.param) {
              try {
                ctx.request.body = JSON.parse(Decrypt(body.param));
              } catch (error) {
                console.error('解密失败（降级模式）:', error);
                // 非强制加密模式下，解密失败仍继续
              }
            }
          }
          await next();
        }
      }
    };
  }

  static getName(): string {
    return 'encrypt';
  }
}
